# 线程基础
# 线程使用方式
# 实现 Runnable 接口
class RunnableImpl implements Runnable {
public void run() {
// ...
}
}
new Thread(new RunnableImpl()).start();
- 函数式接口
new Thread(() -> {
// ...
}).start();
# 实现 Callable 接口
class CallableImpl implements Callable<Integer> {
public Integer call() {
return 123;
}
}
FutureTask<Integer> ft = new FutureTask<>(new CallableImpl());
new Thread(ft).start();
System.out.println(ft.get());
# 继承 Thread 类
同样需要实现 run() 方法,因为 Thread 类实现了 Runable 接口。
class SubThread extends Thread {
public void run() {
// ...
}
}
new SubThread().start();
- 匿名类
new Thread() {
public void run() {
// ...
}
}.start();
# 实现接口 VS 继承 Thread
实现 Runnable 接口相比继承 Thread 类有如下优势
- 可以避免由于 Java 的单继承特性而带来的局限
- 代码能够被多个线程共享
- 线程池只能放入实现 Runable 或 Callable 的类
实现 Runnable 接口和实现 Callable 接口的区别
Runnable 从 1.1 就有,Callable 是 1.5 之后加上去的
实现 Callable 接口的任务线程能返回执行结果
Callable 接口的 call() 方法允许抛出异常,而 Runnable 接口的 run() 方法的异常只能在内部消化,不能继续上抛
一个线程出了异常,应由所在的线程处理,别的线程没有义务或上下文来处理。
加入线程池运行,Runnable 使用 ExecutorService 的 execute 方法,Callable 使用 submit 方法
# 基础线程机制
# Executor
管理多个独立的异步任务的执行,而无需开发者显式地管理线程的生命周期。
- CachedThreadPool:一个任务创建一个线程。
- FixedThreadPool:所有任务只能使用固定大小的线程。
- SingleThreadExecutor:相当于大小为 1 的 FixedThreadPool。
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
// ...
});
executorService.shutdown();
# Daemon
当 JVM 中运行的线程都是守护线程时,JVM 将退出。
Thread thread = new Thread(() -> {
// ...
});
thread.setDaemon(true);
# 线程状态转换

# New
新建状态,创建后尚未启动
# Runnable
可运行状态,可能正在运行,也可能正在等待 CPU 时间片。
包含了操作系统线程状态中的 Running 和 Ready。
# Blocking
阻塞状态,等待获取一个排它锁,如果其线程释放了锁就会结束此状态。
# Waiting
无限期等待状态,等待其他线程显式地唤醒,否则不会被分配 CPU 时间片。
| 进入 | 退出 |
|---|---|
| Object#wait() | Object#notify() / Object#notifyAll() |
| Thread#join() | 被调用的线程执行完毕 |
| LockSupport#park() | - |
# Timed Waiting
限期等待状态。
| 进入 | 退出 |
|---|---|
| Thread#sleep(long millis) | 时间结束 |
| Object#wait(long timeout) | 时间结束 / Object.notify() / Object.notifyAll() |
| Thread#join(long millis) | 时间结束 / 被调用的线程执行完毕 |
| LockSupport#parkNanos | - |
| LockSupport#parkUntil | - |
# Terminated
可以是线程结束任务之后自己结束,或者产生了异常而结束。
# 线程阻塞
# 同步阻塞
运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入“锁池”中。
# 等待阻塞
运行的线程执行 wait() 方法,该线程会释放占用的所有资源,JVM 会把该线程放入“等待池”中。
进入这个状态后,无法自动唤醒,必须由其他线程调用 notify() 或 notifyAll() 方法才能将其唤醒。
# 其他阻塞
运行的线程执行 sleep() 或 join() 方法,或者发出了 I/O 请求时,JVM 会把该线程置为阻塞状态。
当 sleep() 状态超时、join() 等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入就绪状态。
# 线程中断
# interrupt
线程的实例方法 interrupt() 不能立即中断线程,该方法仅告诉线程已经有中断请求,至于是否中断取决于线程内部逻辑。
线程的实例方法 isInterrupted() 可以检测 请求中断标志 为 true 还是 false。
线程的静态方法 interrupted() 也可以检测 请求中断标志,并自动将 请求中断标志 置为 false。
部分可中断的线程方法,会定期执行 isInterrupted() 方法,检测到变化时停止阻塞并抛出 InterruptedException 异常。
在捕获 InterruptedException 异常的时候会自动将 请求中断标志 置为 false。
# stop
已废弃
强制让线程停止有可能使一些清理性的工作得不到完成。
会对锁定的对象进行解锁,导致数据得不到同步处理,出现数据不一致的问题。
# 参考链接
← 理论基础